/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.lvyh.lightframe.sharding.client.util;


import org.apache.commons.lang3.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

public class DateUtils {
    public static final String DATE_FORMAT_10 = "yyyy-MM-dd";
    public static final String DATE_FORMAT_14 = "yyyyMMddHHmmss";
    public static final String DATE_FORMAT_17 = "yyyyMMdd HH:mm:ss";
    public static final String DATE_FORMAT_19 = "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_FORMAT_23 = "yyyy-MM-dd HH:mm:ss.SSS";
    public static final String DATE_FORMAT_19_FORWARD_SLASH = "yyyy/MM/dd HH:mm:ss";
    private static final String MINUS = "-";
    private static final TimeZone chinaZone = TimeZone.getTimeZone("GMT+08:00");
    private static final Locale chinaLocale = Locale.CHINA;

    private DateUtils() {
    }

    /**
     * convert string to date
     *
     * @param dateString
     * @param dateFormat
     * @return
     * @throws ParseException
     */
    public static Date parseDate(String dateString, String dateFormat) throws ParseException {
        if (StringUtils.isEmpty(dateFormat)) {
            dateFormat = switchDateFormat(dateString);
        }
        return new SimpleDateFormat(dateFormat).parse(dateString);
    }

    /**
     * convert string to date
     *
     * @param dateString
     * @return
     * @throws ParseException
     */
    public static Date parseDate(String dateString) throws ParseException {
        return parseDate(dateString, switchDateFormat(dateString));
    }

    /**
     * switch date format
     *
     * @param dateString
     * @return
     */
    private static String switchDateFormat(String dateString) {
        int length = dateString.length();
        switch (length) {
            case 19:
                if (dateString.contains(MINUS)) {
                    return DATE_FORMAT_19;
                } else {
                    return DATE_FORMAT_19_FORWARD_SLASH;
                }
            case 17:
                return DATE_FORMAT_17;
            case 14:
                return DATE_FORMAT_14;
            case 10:
                return DATE_FORMAT_10;
            default:
                throw new IllegalArgumentException("can not find date format for：" + dateString);
        }
    }

    /**
     * Format date
     * <p>
     * yyyy-MM-dd HH:mm:ss
     *
     * @param date
     * @return
     */
    public static String format(Date date) {
        return format(date, null);
    }


    public static String formatYmdHis(long milliseconds) {
        Calendar ca = Calendar.getInstance(chinaZone, chinaLocale);
        ca.setTimeInMillis(milliseconds);
        StringBuilder sbd = new StringBuilder();
        sbd.append(ca.get(Calendar.YEAR)).append('-');
        int month = 1 + ca.get(Calendar.MONTH);
        if (month < 10) {
            sbd.append('0');
        }
        sbd.append(month).append('-');
        int day = ca.get(Calendar.DAY_OF_MONTH);
        if (day < 10) {
            sbd.append('0');
        }
        sbd.append(day).append(' ');
        int hour = ca.get(Calendar.HOUR_OF_DAY);
        if (hour < 10) {
            sbd.append('0');
        }
        sbd.append(hour).append(':');
        int minute = ca.get(Calendar.MINUTE);
        if (minute < 10) {
            sbd.append('0');
        }
        sbd.append(minute).append(':');
        int second = ca.get(Calendar.SECOND);
        if (second < 10) {
            sbd.append('0');
        }
        sbd.append(second);
        return sbd.toString();
    }

    /**
     * Format date
     *
     * @param date
     * @param dateFormat
     * @return
     */
    public static String format(Date date, String dateFormat) {
        if (date == null) {
            return "";
        }
        if (StringUtils.isEmpty(dateFormat)) {
            dateFormat = DATE_FORMAT_19;
        }
        return new SimpleDateFormat(dateFormat).format(date);
    }

    public static Date addDays(long mills, int days) {
        Calendar ca = Calendar.getInstance(chinaZone, chinaLocale);
        ca.setTimeInMillis(mills);
        ca.set(Calendar.SECOND, 0);
        ca.set(Calendar.MILLISECOND, 0);
        ca.add(Calendar.DAY_OF_MONTH, days);
        return ca.getTime();
    }

    public static Date addDays(Date date, int nMonths) {
        return addDays(date.getTime(), nMonths);
    }

    public static String formatYmdHisS(long milliseconds) {
        Calendar ca = Calendar.getInstance(chinaZone, chinaLocale);
        ca.setTimeInMillis(milliseconds);
        StringBuilder sbd = new StringBuilder();
        sbd.append(ca.get(Calendar.YEAR)).append('-');
        int month = 1 + ca.get(Calendar.MONTH);
        if (month < 10) {
            sbd.append('0');
        }
        sbd.append(month).append('-');
        int day = ca.get(Calendar.DAY_OF_MONTH);
        if (day < 10) {
            sbd.append('0');
        }
        sbd.append(day).append(' ');
        int hour = ca.get(Calendar.HOUR_OF_DAY);
        if (hour < 10) {
            sbd.append('0');
        }
        sbd.append(hour).append(':');
        int minute = ca.get(Calendar.MINUTE);
        if (minute < 10) {
            sbd.append('0');
        }
        sbd.append(minute).append(':');
        int second = ca.get(Calendar.SECOND);
        if (second < 10) {
            sbd.append('0');
        }
        sbd.append(second);
        int ms = ca.get(Calendar.MILLISECOND);
        if (ms > 0) {
            sbd.append('.').append(ms);
        }
        return sbd.toString();
    }
}
